#include "dispatcher.h"
#include "Process.h"

#include <map>
#include <iostream>
#include <string>

typedef int (*Func)(vector<string>, Process* process);

map <string,Func> dispatch;

int unToken(vector<string> vec ,int start, char* buf) {
	string tmp;
	for (vector<string>::iterator it=vec.begin()+start ; it < vec.end(); it++ )
		tmp += string(*it) + " ";
	strcpy(buf,tmp.c_str());
	buf[strlen(buf)-1] = '\0';
	return 0;
}

int toPermissions(const string& arg) {
	if (arg=="read-only" || arg=="r")
		return READ;
	if (arg=="read-and-write" || arg=="rw")
		return WRITE;
	return -1;
}

int isNum(const char* str) {
	for(unsigned int i = 0; i < strlen(str); i++)
		if (!isdigit(str[i]))
			return false;
	return true;
}


int mkdir(vector<string> args, Process* process) {
	if (args.size() == 1)
		return process->mkdir(args[0].c_str());
	cout << "correct syntax is: mkdir <dir-name>  - makes a directory with the given name. " << endl;
	return -1;
}

int create(vector<string> args, Process* process) {
	if (args.size() == 2) {
		int perm = toPermissions(args[1]);
		if (perm != -1)
			return process->create(args[0].c_str(),perm);
		cout <<"wrong permissions: expected [ r | rw ], given " << args[1] << endl;
		return -1;
	}
	cout << "correct syntax is: create <filename> <read-only | read-and-write>" << endl;
	return -1;
}

int hdlink(vector<string> args, Process* process) {
	if (args.size() == 2)
		return process->hdlink(args[0].c_str(),args[1].c_str());
	cout << "correct syntax is: hdlink <file-to-link-to> <new-file-name>" << endl;
	return -1;
}

int sflink(vector<string> args, Process* process) {
	if (args.size() == 2)
		return process->sflink(args[0].c_str(),args[1].c_str());
	cout << "correct syntax is: sflink <file-to-link-to> <new-file-name>" << endl;
	return -1;
}

int open(vector<string> args, Process* process) {
	if (args.size() == 2) {
		int perm = toPermissions(args[1]);
		if (perm != -1)
			return process->open(args[0].c_str(),perm);
		cout <<"wrong permissions: expected [ r | rw ], given " << args[1] << endl;
		return -1;
	}
	cout << "correct syntax is: open <file-name> <read-only | read-and-write>" << endl;
	return -1;
}

int close(vector<string> args, Process* process) {
	if (args.size() == 1) {
		if (isNum(args[0].c_str()))
			return process->close(atoi(args[0].c_str()));
		cout <<"illegal fd: given " << args[0] << endl;
		return -1;
	}
	cout << "correct syntax is: close <fd>" << endl;
	return -1;
}

int read(vector<string> args, Process* process) {
	if (args.size() == 2) {
		if (isNum(args[0].c_str()) && isNum(args[1].c_str()))
			return process->read(atoi(args[0].c_str()),atoi(args[1].c_str()));
		if (!isNum(args[0].c_str()))
			cout <<"illegal fd: given " << args[0] << endl;
		if (!isNum(args[1].c_str()))
			cout <<"illegal num-bytes: given " << args[1] << endl;
		return -1;
	}
	cout << "correct syntax is: read <fd> <num-bytes>" << endl;
	return -1;
}

int write(vector<string> args, Process* process) {
	if (args.size() >= 2) {
		if (isNum(args[0].c_str())) {
			char buf[4096];
			unToken(args,1,buf);
			return process->write(atoi(args[0].c_str()),buf);
		}
		cout <<"illegal fd: given " << args[0] << endl;
		return -1;
	}
	cout << "correct syntax is: write <fd> <string>" << endl;
	return -1;
}

int writeFile(vector<string> args, Process* process) {
	if (args.size() == 2)
		return process->writeFile(atoi(args[0].c_str()),args[1].c_str());
	cout << "correct syntax is: writeFile <fd> <linux-fileName>" << endl;
	return -1;
}

int lck_rd(vector<string> args, Process* process) {
	if (args.size() == 1) {
		if (isNum(args[0].c_str()))
			return process->lck_rd(atoi(args[0].c_str()));
		cout <<"illegal fd: given " << args[0] << endl;
		return -1;
	}
	cout << "correct syntax is: lck_rd <fd>" << endl;
	return -1;
}

int lck_wr(vector<string> args, Process* process) {
	if (args.size() == 1) {
		if (isNum(args[0].c_str()))
			return process->lck_wr(atoi(args[0].c_str()));
		cout <<"illegal fd: given " << args[0] << endl;
		return -1;
	}
	cout << "correct syntax is: lck_wr <fd> " << endl;
	return -1;
}

int rlslck_rd(vector<string> args, Process* process) {
	if (args.size() == 1) {
		if (isNum(args[0].c_str()))
			return process->rlslck_rd(atoi(args[0].c_str()));
		cout <<"illegal fd: given " << args[0] << endl;
		return -1;
	}
	cout << "correct syntax is: rlslck_rd <fd>" << endl;
	return -1;
}

int rlslck_wr(vector<string> args, Process* process) {
	if (args.size() == 1) {
		if (isNum(args[0].c_str()))
			return process->rlslck_wr(atoi(args[0].c_str()));
		cout <<"illegal fd: given " << args[0] << endl;
		return -1;
	}
	cout << "correct syntax is: rlslck_wr <fd>" << endl;
	return -1;
}

int lseek(vector<string> args, Process* process) {
	if (args.size() == 2) {
		if (isNum(args[0].c_str()) && isNum(args[1].c_str()))
			return process->lseek(atoi(args[0].c_str()),atoi(args[1].c_str()));
		if (!isNum(args[0].c_str()))
			cout <<"illegal fd: given " << args[0] << endl;
		if (!isNum(args[1].c_str()))
			cout <<"illegal offset: given " << args[1] << endl;
		return -1;
	}
	cout << "correct syntax is: lseek <fd> <offset>" << endl;
	return -1;
}
int rm(vector<string> args, Process* process) {
	if (args.size() == 1)
		return process->rm(args[0].c_str());
	cout << "correct syntax is: rm <file-name>" << endl;
	return -1;
}
int rmdir(vector<string> args, Process* process) {
	if (args.size() == 1)
		return process->rmdir(args[0].c_str());
	cout << "correct syntax is: rmdir <dirname> " << endl;
	return -1;
}

int rmdir_r(vector<string> args, Process* process) {
	if (args.size() == 1)
		return process->rmdir_r(args[0].c_str());
	cout << "correct syntax is: rmdir_r <dirname>" << endl;
	return -1;
}


int cd(vector<string> args, Process* process) {
	if (args.size() == 1)
		return process->cd(args[0].c_str());
	cout << "correct syntax is: cd <dirname>" << endl;
	return -1;
}


int mv(vector<string> args, Process* process) {
	if (args.size() == 2)
		return process->mv(args[0].c_str(),args[1].c_str());
	cout << "correct syntax is: mv <old-file-name> <new-file-name>" << endl;
	return -1;
}

int ls(vector<string> args, Process* process) {
	if (args.size() == 1) {
		return process->ls(args[0].c_str());
	}
	if (args.size() == 0)
		return process->ls(".");
	cout << "correct syntax is: ls <dirname>" << endl;
	return -1;
}

int printFdTable(vector<string> args, Process* process) {
	return process->fd();
}

int runCmd(vector<string> args, Process* process) {
	if (args.size() == 0)
		return -1;
	string cmd(args[0]);
	cout << "*" << cmd << "*" << endl;
	Func f = dispatch[cmd];
	if (f != NULL) {
		args.erase(args.begin());
		int ret = f(args, process);
		//if(ret!=0)
		cout << ret <<endl;
		return ret;
	}
	cout << cmd << ": command not found." << endl;
	return -1;
}

void initDispatcher() {
	dispatch["mkdir"] = mkdir;
	dispatch["create"] = create;
	dispatch["cr"] = create;
	dispatch["hdlink"] = hdlink;
	dispatch["hlink"] = hdlink;
	dispatch["sflink"] = sflink;
	dispatch["slink"] = sflink;
	dispatch["open"] = open;
	dispatch["close"] = close;
	dispatch["read"] = read;
	dispatch["write"] = write;
	dispatch["writeFile"] = writeFile;
	dispatch["writefile"] = writeFile;
	dispatch["lck_rd"] = lck_rd;
	dispatch["lck_wr"] = lck_wr;
	dispatch["rlslck_rd"] = rlslck_rd;
	dispatch["rls_rd"] = rlslck_rd;
	dispatch["rlslck_wr"] = rlslck_wr;
	dispatch["rls_wr"] = rlslck_wr;
	dispatch["lseek"] = lseek;
	dispatch["seek"] = lseek;
	dispatch["rm"] = rm;
	dispatch["rmdir"] = rmdir;
	dispatch["rmdir_r"] = rmdir_r;
	dispatch["ls"] = ls;
	dispatch["mv"] = mv;
	dispatch["cd"] = cd;
	dispatch["fd"] = printFdTable;
}
